package cn.openea.perpartner.expert.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.openea.perpartner.common.core.manager.AsyncManager;
import cn.openea.perpartner.common.core.text.Convert;
import cn.openea.perpartner.common.core.web.domain.AjaxResult;
import cn.openea.perpartner.expert.web.domain.dto.MsgDto;
import cn.openea.perpartner.expert.web.domain.dto.SelectDto;
import cn.openea.perpartner.expert.web.domain.dto.SignupDto;
import cn.openea.perpartner.expert.web.domain.dto.TimelineDto;
import cn.openea.perpartner.expert.web.domain.entity.Delivery;
import cn.openea.perpartner.expert.web.domain.entity.ExpertJob;
import cn.openea.perpartner.expert.web.domain.entity.Signup;
import cn.openea.perpartner.expert.web.mapper.ExpertJobMapper;
import cn.openea.perpartner.expert.web.service.*;
import cn.openea.perpartner.meily.web.entity.TaskHall;
import cn.openea.perpartner.meily.web.entity.Todo;
import cn.openea.perpartner.meily.web.service.ITaskHallService;
import cn.openea.perpartner.meily.web.service.ITodoService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 专家协作需求表(Job)表服务实现类
 *
 * @author Weird077
 * @since 2023-06-19 11:45:59
 */
@Service("expertService")
public class ExpertJobServiceImpl extends ServiceImpl<ExpertJobMapper, ExpertJob> implements IExpertJobService {
    @Value("${sso.url}")
    private String ssoUri;
    private JSONObject userInfo;
    @Resource
    private ITaskHallService hallService;
    @Resource
    private ITodoService todoService;
    @Resource
    private ISignupService signupService;
    @Resource
    private IDeliveryService deliveryService;
    @Resource
    private ISendMsgService sendMsgService;
    @Resource
    private ITimelineService timelineService;
    private static final String TASK_STATE_SIGNUP = "火热报名";

    @Override
    public ExpertJob getByTaskNum(String taskNum) {
        return getOne(Wrappers.<ExpertJob>lambdaQuery().eq(ExpertJob::getTaskNum, taskNum));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean publishJob(ExpertJob job) {
        boolean isSuccess = save(job);
        if (isSuccess) {
            TaskHall hall = TaskHall.builder()
                    .taskNumber(job.getTaskNum())
                    .taskName(job.getSubject())
                    .taskDetail(job.getDetails())
                    .taskPrice(job.getBudget())
                    .taskType("专家协作")
                    .taskState("火热报名")
                    .taskStatus("上架")
                    .taskKeyword(job.getKeywords())
                    .collectType("market")
                    .taskLabel("工作")
                    .taskColor("#3b79fe")
                    .imageUrl(job.getImageUrl())
                    .createUser(job.getCreateUser())
                    .taskCurrentId(Convert.toStr(job.getJobId()))
                    .taskHistoryId(Convert.toStr(job.getJobId()))
                    .taskUrl("/pages_private_scene1/ExpertCooperate/grabJob?taskNumber=" + job.getTaskNum())
                    .build();
            isSuccess = hallService.insert(hall);
        }
        //异步发送时间轴消息
        AsyncManager.me().execute(timelineService.publishJob(job));
        return isSuccess;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult grabJob(ExpertJob job) {
        TaskHall task = hallService.getOne(Wrappers.<TaskHall>lambdaQuery()
                .eq(TaskHall::getTaskNumber, job.getTaskNum()));
        if (BeanUtil.isEmpty(task)) {
            return AjaxResult.error("工作已被抢或已下架...");
        }
        if (job.getCreateUser().equals(task.getCreateUser())) {
            return AjaxResult.error("不允许抢本人发布的工作...");
        }
        if (!TASK_STATE_SIGNUP.equals(task.getTaskState())) {

            return AjaxResult.error("抢工作失败，当前工作已结束报名...");
        }
        //判断是否已截止报名
        ExpertJob expertJob = getByTaskNum(job.getTaskNum());
        DateTime deadline = DateUtil.parseDate(expertJob.getDeadline());
        deadline = DateUtil.offsetDay(deadline, 1);
        if (DateUtil.compare(deadline, DateUtil.date()) < 0) {
            return AjaxResult.error("报名参与工作时间已截止...");
        }
        //判断是否已获得参与机会
        StringBuilder sb = new StringBuilder();
        if (StrUtil.isNotBlank(task.getTaskUser())) {
            sb.append(task.getTaskUser());
        }
        if (StrUtil.isNotBlank(task.getTaskAuthor())) {
            sb.append(",").append(task.getTaskAuthor());
        }
        String taskAuthor = sb.toString();
        if (taskAuthor.contains(job.getCreateUser())) {
            AjaxResult success = AjaxResult.success("您已获得参与机会...");
            success.put("url", "/pages_private_scene1/ExpertCooperate/partnerApply?taskNumber=" + task.getTaskNumber());
            return success;
        }
        // 追加参与人
        if (StrUtil.isBlank(task.getTaskUser())) {
            task.setTaskUser(job.getCreateUser());
        } else {
            task.setTaskUser(task.getTaskUser() + "," + job.getCreateUser());
        }
        //增加用户工作待办
        Todo todo = Todo.builder()
                .taskId(task.getTaskId())
                .subject(task.getTaskName())
                .reqNumber(task.getTaskNumber())
                .userId(job.getCreateUser())
                .startTime(DateUtil.now())
                .status("Current")
                .nodeName(TASK_STATE_SIGNUP)
                .prvUserId(task.getCreateUser())
                .prvNickName(getUserNickName(task.getCreateUser()))
                .prvUserAvatar(getUserAvatar(task.getCreateUser()))
                .minAppUri("/pages_private_scene1/ExpertCooperate/partnerApply?taskNumber=" + task.getTaskNumber())
                .todoType("工作机会")
                .build();
        if (hallService.updateById(task)) {
            todoService.addToDoData(todo);
        }
        AjaxResult success = AjaxResult.success("抢工作成功，您已获得参与机会...");
        success.put("url", "/pages_private_scene1/ExpertCooperate/partnerApply?taskNumber=" + task.getTaskNumber());
        return success;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean partnerSignup(SignupDto dto) {
        //1、写入报名表
        boolean isSuccess = signupService.save(Signup.builder()
                .jobId(dto.getJobId())
                .taskNum(dto.getTaskNum())
                .userId(dto.getUserId())
                .nickName(dto.getNickName())
                .status("初选中")
                .bio(dto.getBio())
                .projectCase(dto.getProjectCase().toJSONString())
                .build());
        //2、更新待办状态
        if (isSuccess) {
            isSuccess = todoService.updateToDoToDone(dto.getUserId(), dto.getTaskNum());
        }
        //3、发送待办给需求发布者
        if (isSuccess) {
            ExpertJob job = getByTaskNum(dto.getTaskNum());
            Todo todo = Todo.builder()
                    .taskId(Convert.toStr(dto.getJobId()))
                    .subject(job.getSubject())
                    .reqNumber(dto.getTaskNum())
                    .userId(job.getCreateUser())
                    .startTime(DateUtil.now())
                    .status("Current")
                    .nodeName("待初选")
                    .prvUserId(dto.getUserId())
                    .prvNickName(getUserNickName(dto.getUserId()))
                    .prvUserAvatar(getUserAvatar(dto.getUserId()))
                    .minAppUri("/pages_private_scene1/ExpertCooperate/filterPartner?taskNumber=" + dto.getTaskNum())
                    .build();
            isSuccess = todoService.saveOrUpdateToDoDataByNodeName(todo);
            //异步发送时间轴消息
            AsyncManager.me().execute(timelineService.partnerSignup(todo));
            //异步发送小程序消息通知
            AsyncManager.me().execute(sendMsgService.partnerSignup(MsgDto.builder()
                    .userId(job.getCreateUser())
                    .partnerId(dto.getUserId())
                    .taskNum(dto.getTaskNum())
                    .subject(job.getSubject())
                    .minAppUri(todo.getMinAppUri())
                    .taskId(todo.getTaskId())
                    .build()));
        }
        return isSuccess;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean userPreselect(SelectDto dto) {
        ExpertJob job = getByTaskNum(dto.getTaskNum());
        job.setRemark(dto.getRemark());
        updateById(job);
        //1、更新待办状态ARC
        todoService.updateToDoToDone(dto.getUserId(), dto.getTaskNum());

        if ("reject".equals(dto.getAction())) {
            signupService.update(Wrappers.<Signup>lambdaUpdate()
                    .set(Signup::getStatus, "初选不通过")
                    .eq(Signup::getTaskNum, job.getTaskNum()));
        }
        if (!"reject".equals(dto.getAction())) {
            //2、查询所有报名拍档
            LambdaQueryWrapper<Signup> signupWrapper = Wrappers.lambdaQuery();
            signupWrapper.eq(Signup::getTaskNum, job.getTaskNum());
            List<String> signupList = signupService.list(signupWrapper).stream()
                    .map(Signup::getUserId).collect(Collectors.toList());
            //3、取选中的拍档
            List<String> selectedUser = StrUtil.splitTrim(dto.getUsers(), ",");
            //4、更新报名表状态
            signupService.update(Wrappers.<Signup>lambdaUpdate()
                    .set(Signup::getStatus, "通过初选")
                    .eq(Signup::getTaskNum, job.getTaskNum())
                    .in(Signup::getUserId, selectedUser));
            //5、给通过初选的拍档发送工作待办
            for (String userId : selectedUser) {
                Todo todo = Todo.builder()
                        .taskId(Convert.toStr(job.getJobId()))
                        .subject(job.getSubject())
                        .reqNumber(job.getTaskNum())
                        .userId(userId)
                        .startTime(DateUtil.now())
                        .status("Current")
                        .nodeName("通过初选")
                        .prvUserId(dto.getUserId())
                        .prvNickName(getUserNickName(dto.getUserId()))
                        .prvUserAvatar(getUserAvatar(dto.getUserId()))
                        .minAppUri("/pages_private_scene1/ExpertCooperate/partnerApplyAgain?taskNumber=" + dto.getTaskNum())
                        .build();
                todoService.addToDoData(todo);
                //6、异步给同过初选的拍档发送小程序消息通知
                AsyncManager.me().execute(sendMsgService.userPreselect(todo));
            }
            //7、移除通过初选的拍档
            signupList.removeAll(selectedUser);
            //8、将剩余未通过初选的拍档更新状态为不通过
            if (CollUtil.isNotEmpty(signupList)) {
                signupService.update(Wrappers.lambdaUpdate(Signup.class)
                        .set(Signup::getStatus, "初选不通过")
                        .eq(Signup::getTaskNum, job.getTaskNum())
                        .in(Signup::getUserId, signupList));
                //9、异步给未通过初选的拍档发送小程序消息通知
                for (String partnerId : signupList) {
                    AsyncManager.me().execute(sendMsgService.userPreselectReject(MsgDto.builder()
                            .userId(job.getCreateUser())
                            .partnerId(partnerId)
                            .taskNum(job.getTaskNum())
                            .subject(job.getSubject())
                            .minAppUri("/pages_private_scene1/ExpertCooperate/jobInfo?taskNumber=" + job.getTaskNum())
                            .taskId(Convert.toStr(job.getJobId()))
                            .build()));
                }
            }
        }
        //异步发送时间轴消息
        AsyncManager.me().execute(timelineService.userPreselect(TimelineDto.builder()
                .userId(dto.getUserId())
                .ticketNum(dto.getTaskNum())
                .build()));

        //9、都不通过，需求下架
        String taskState = "需求下架";
        String status = "下架";
        if (!"reject".equals(dto.getAction())) {
            taskState = "项目进行中";
            status = "上架";
        }
        return hallService.update(Wrappers.<TaskHall>lambdaUpdate().eq(TaskHall::getTaskNumber, dto.getTaskNum())
                .set(TaskHall::getTaskState, taskState)
                .set(TaskHall::getTaskStatus, status));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean partnerReselect(SignupDto dto) {
        ExpertJob job = getByTaskNum(dto.getTaskNum());
        //1.更新拍档报名状态为--待复选
        signupService.update(Wrappers.<Signup>lambdaUpdate()
                .set(Signup::getStatus, "待复选")
                .set(Signup::getBidPrice, dto.getBidPrice())
                .set(Signup::getWorkContent, dto.getWorkContent().toJSONString())
                .set(Signup::getDeliveryDate, dto.getDeliveryDate())
                .eq(Signup::getTaskNum, dto.getTaskNum())
                .eq(Signup::getUserId, dto.getUserId()));
        //2、更新待办状态ARC
        todoService.updateToDoToDone(dto.getUserId(), dto.getTaskNum());
        Todo todoData = Todo.builder()
                .taskId(Convert.toStr(job.getJobId()))
                .subject(job.getSubject())
                .reqNumber(job.getTaskNum())
                .userId(job.getCreateUser())
                .startTime(DateUtil.now())
                .status("Current")
                .nodeName("待复选")
                .prvUserId(dto.getUserId())
                .prvNickName(getUserNickName(dto.getUserId()))
                .prvUserAvatar(getUserAvatar(dto.getUserId()))
                .minAppUri("/pages_private_scene1/ExpertCooperate/filterPartnerAgain?taskNumber=" + dto.getTaskNum())
                .build();
        //3、异步发送时间轴消息
        AsyncManager.me().execute(timelineService.partnerReselect(todoData));
        //4、异步给需求发布者发送小程序消息通知
        AsyncManager.me().execute(sendMsgService.partnerReselect(todoData));
        //5、发送待办给需求发布者
        return todoService.saveOrUpdateToDoDataByNodeName(todoData);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean userReselect(SelectDto dto) {
        //1、更新需求
        ExpertJob job = getByTaskNum(dto.getTaskNum());
        job.setWorkContent(dto.getWorkContent().toJSONString());
        job.setFinalPrice(dto.getFinalPrice());
        updateById(job);
        //2、更新待办状态ARC
        todoService.updateToDoToDone(dto.getUserId(), dto.getTaskNum());
        if ("reject".equals(dto.getAction())) {
            signupService.update(Wrappers.<Signup>lambdaUpdate()
                    .set(Signup::getStatus, "复选不通过")
                    .eq(Signup::getTaskNum, job.getTaskNum()));
        }
        if (!"reject".equals(dto.getAction())) {
            //3、查询所有报名拍档
            LambdaQueryWrapper<Signup> signupWrapper = Wrappers.lambdaQuery(Signup.class)
                    .eq(Signup::getTaskNum, job.getTaskNum())
                    .eq(Signup::getStatus, "待复选");
            List<String> signupList = signupService.list(signupWrapper).stream()
                    .map(Signup::getUserId).collect(Collectors.toList());
            //4、取选中的拍档
            List<String> selectedUser = StrUtil.splitTrim(dto.getUsers(), ",");
            //5、更新拍档报名状态为--通过初选
            signupService.update(Wrappers.<Signup>lambdaUpdate()
                    .set(Signup::getStatus, "已中标")
                    .set(Signup::getFinalPrice, dto.getFinalPrice())
                    .set(Signup::getDeliveryDate, dto.getDeliveryDate())
                    .set(Signup::getFixWorkContent, dto.getWorkContent().toJSONString())
                    .eq(Signup::getTaskNum, job.getTaskNum())
                    .in(Signup::getUserId, selectedUser));
            //6、给中标的拍档发送工作待办
            for (String userId : selectedUser) {
                Todo todo = Todo.builder()
                        .taskId(Convert.toStr(job.getJobId()))
                        .subject(job.getSubject())
                        .reqNumber(job.getTaskNum())
                        .userId(userId)
                        .startTime(DateUtil.now())
                        .status("Current")
                        .nodeName("已中标")
                        .prvUserId(dto.getUserId())
                        .prvNickName(getUserNickName(dto.getUserId()))
                        .prvUserAvatar(getUserAvatar(dto.getUserId()))
                        .minAppUri("/pages_private_scene1/ExpertCooperate/partnerConfirm?taskNumber=" + dto.getTaskNum())
                        .build();
                todoService.addToDoData(todo);
                //7、异步给同过初选的拍档发送小程序消息通知
                AsyncManager.me().execute(sendMsgService.userReselect(todo));
            }
            //8、移除通过复选的拍档
            signupList.removeAll(selectedUser);
            //9、将剩余未通过初选的拍档更新状态为不通过
            if (!signupList.isEmpty()) {
                signupService.update(Wrappers.lambdaUpdate(Signup.class)
                        .set(Signup::getStatus, "复选不通过")
                        .eq(Signup::getTaskNum, job.getTaskNum())
                        .eq(Signup::getStatus, "待复选")
                        .in(Signup::getUserId, signupList));
                for (String partnerId : signupList) {
                    AsyncManager.me().execute(sendMsgService.userReselectReject(MsgDto.builder()
                            .userId(job.getCreateUser())
                            .taskNum(job.getTaskNum())
                            .partnerId(partnerId)
                            .taskId(Convert.toStr(job.getJobId()))
                            .subject(job.getSubject())
                            .minAppUri("/pages_private_scene1/ExpertCooperate/jobInfo?taskNumber=" + job.getTaskNum())
                            .build()));
                }
            }
        }
        //10、异步发送时间轴消息
        AsyncManager.me().execute(timelineService.userReselect(TimelineDto.builder()
                .userId(dto.getUserId())
                .ticketNum(dto.getTaskNum())
                .build()));
        //11、需求下架
        return hallService.update(Wrappers.<TaskHall>lambdaUpdate()
                .eq(TaskHall::getTaskNumber, dto.getTaskNum())
                .set(TaskHall::getTaskState, "需求下架")
                .set(TaskHall::getTaskStatus, "下架"));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean partnerConfirm(SignupDto dto) {
        //1、更新待办状态ARC
        todoService.updateToDoToDone(dto.getUserId(), dto.getTaskNum());
        //2、取需求详情
        ExpertJob job = getByTaskNum(dto.getTaskNum());
        //3、取项目期数
        int count = job.getPaymentType().split(":").length;
        JSONObject first = dto.getWorkContent().getJSONObject(0);
        Delivery delivery = Delivery.builder()
                .taskNumber(job.getTaskNum())
                .partnerId(dto.getUserId())
                .partnerName(dto.getNickName())
                .initiatorId(job.getCreateUser())
                .initiatorName(job.getNickName())
                .totalPeriods(Convert.toStr(count))
                .subTaskSortNum("1")
                .contentAndRequire(first.getString("content"))
                .deliveryDate(first.getString("subDate"))
                .subTaskPrice(first.getString("brokerage"))
                .workSubject(job.getSubject())
                .budget(job.getBudget())
                .paymentType(job.getPaymentType())
                .workEndDate(job.getDeliveryDate())
                .build();
        deliveryService.save(delivery);

        //4、异步发送时间轴消息
        AsyncManager.me().execute(timelineService.partnerConfirm(TimelineDto.builder()
                .userId(dto.getUserId())
                .ticketNum(dto.getTaskNum())
                .eventDetail("项目已启动，" + job.getDeadline() + "前交付第1期成果（1/" + count + "）")
                .build()));
        Todo todoData = Todo.builder()
                .taskId(Convert.toStr(job.getJobId()))
                .subject(job.getSubject())
                .reqNumber(job.getTaskNum())
                .userId(dto.getUserId())
                .startTime(DateUtil.now())
                .status("Current")
                .nodeName("提交成果")
                .prvUserId(dto.getUserId())
                .prvNickName(getUserNickName(dto.getUserId()))
                .prvUserAvatar(getUserAvatar(dto.getUserId()))
                .minAppUri("/pages_private_scene1/ExpertCooperate/partnerDelivery?taskNumber=" + dto.getTaskNum() + "&deliveryId=" + delivery.getDeliveryId())
                .build();
        //5、异步发送小程序消息通知
        AsyncManager.me().execute(sendMsgService.partnerConfirm(todoData));
        //6、发送工作待办
        return todoService.addToDoData(todoData);
    }


    @Override
    public boolean userEvaluate(ExpertJob job) {
        //1、异步发送时间轴消息
        AsyncManager.me().execute(timelineService.userEvaluate(TimelineDto.builder()
                .userId(job.getCreateUser())
                .ticketNum(job.getTaskNum())
                .eventDetail("项目已完成")
                .eventDetail("项目完结")
                .build()));
        //2、异步发送小程序消息通知
        AsyncManager.me().execute(sendMsgService.userEvaluate(MsgDto.builder()
                .userId(job.getCreateUser())
                .taskNum(job.getTaskNum())
                .subject(job.getSubject())
                .minAppUri("/pages_private_scene1/ExpertCooperate/jobInfo?taskNumber=" + job.getTaskNum())
                .build()));
        //3、更新待办状态ARC
        return todoService.updateToDoToDone(job.getCreateUser(), job.getTaskNum());
    }

    private String getUserAvatar(String userId) {
        if (ObjectUtil.isNull(userInfo)) {
            userInfo = getUserData(userId);
        }
        return userInfo.getString("avatar");
    }

    private String getUserNickName(String userId) {
        if (ObjectUtil.isNull(userInfo)) {
            userInfo = getUserData(userId);
        }
        return userInfo.getString("nickName");
    }

    private JSONObject getUserData(String userId) {
        JSONObject wxObject = new JSONObject();
        String result = HttpUtil.get(ssoUri + "/user/cache/" + userId);
        if (StrUtil.isNotBlank(result)) {
            wxObject = JSON.parseObject(result);
        }
        return wxObject.getJSONObject("data");
    }
}

